/**
 * fshows.com
 * Copyright (C) 2013-2020 All Rights Reserved.
 */
package com.fshows.leshuapay.sdk.client.impl;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.fshows.leshuapay.sdk.client.LeshuaShareClient;
import com.fshows.leshuapay.sdk.exception.LeshuaException;
import com.fshows.leshuapay.sdk.request.LeshuaBizRequest;
import com.fshows.leshuapay.sdk.response.LeshuaBaseResponse;
import com.fshows.leshuapay.sdk.util.ReqSerialNoUtil;
import com.fshows.leshuapay.sdk.util.SignUtil;
import com.fshows.leshuapay.sdk.util.ValidateUtil;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.apache.http.HttpEntity;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.ContentType;
import org.apache.http.entity.mime.HttpMultipartMode;
import org.apache.http.entity.mime.MultipartEntityBuilder;
import org.apache.http.entity.mime.content.StringBody;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.util.EntityUtils;

import java.io.IOException;
import java.nio.charset.Charset;
import java.util.ArrayList;
import java.util.List;


/**
 * @author linzy
 * @version LeshuaShareClientImpl.java, v 0.1 20210-05-06 11:40 AM linzy
 */
@Slf4j
@Data
public class LeshuaShareClientImpl implements LeshuaShareClient {

    /**
     * 从connectManager获取Connection 超时时间
     */
    private static final int CONNECTION_REQUEST_TIMEOUT = 5000;

    /**
     * 读取数据的超时时间
     */
    private static final int SOCKET_TIMEOUT = 10000;

    /**
     * 连接超时时间
     */
    private static final int CONNECT_TIMEOUT = 6000;

    /**
     * 非对象返回
     */
    private static final String JSON_ARRAY_URL_LIST = "/share-merchant/queryBind";

    /**
     * 商户服务地址
     */
    private String serverUrl;

    /**
     * 服务商编号
     */
    private String agentId;

    /**
     * 服务商私钥
     */
    private String privateKey;

    /**
     * 请求超时时间，单位毫秒
     */
    private Integer timeout;

    /**
     * @param serverUrl  商户地址
     * @param agentId    服务商编号
     * @param privateKey 服务商私钥
     * @param timeout    毫秒
     */
    public LeshuaShareClientImpl(String serverUrl, String agentId, String privateKey, Integer timeout) {
        this.serverUrl = serverUrl;
        this.agentId = agentId;
        this.privateKey = privateKey;
        this.timeout = timeout;
    }

    @Override
    public <T> LeshuaBaseResponse<T> execute(LeshuaBizRequest<T> request, String url, Integer timeout) throws LeshuaException {
        long costTimeStart = System.currentTimeMillis();
        ValidateUtil.validateWithThrow(request);
        String responseStr = null;
        //获取签名值
        String sign = SignUtil.getMerchantSign(request, privateKey);
        RequestConfig requestConfig = null;
        if (timeout == null || timeout <= 0) {
            requestConfig = RequestConfig.custom().setConnectionRequestTimeout(CONNECTION_REQUEST_TIMEOUT)
                    .setSocketTimeout(SOCKET_TIMEOUT).setConnectTimeout(CONNECT_TIMEOUT).build();
        } else {
            requestConfig = RequestConfig.custom().setConnectionRequestTimeout(timeout)
                    .setSocketTimeout(timeout).setConnectTimeout(timeout).build();
        }
        HttpPost httppost = new HttpPost(serverUrl + url);
        httppost.setConfig(requestConfig);
        MultipartEntityBuilder multipartEntityBuilder = MultipartEntityBuilder.create();
        multipartEntityBuilder.setMode(HttpMultipartMode.BROWSER_COMPATIBLE);
        multipartEntityBuilder.setCharset(Charset.forName(SignUtil.DEFAULT_CHARSET));
        String reqSerialNo = ReqSerialNoUtil.getReqSerialNo();
        //代理商编号
        multipartEntityBuilder.addPart("agentId", new StringBody(agentId, ContentType.APPLICATION_JSON));
        //版本
        multipartEntityBuilder.addPart("version", new StringBody(SignUtil.DEFAULT_VERSION, ContentType.APPLICATION_JSON));
        //请求流水号
        multipartEntityBuilder.addPart("reqSerialNo", new StringBody(reqSerialNo, ContentType.APPLICATION_JSON));
        //数据内容
        String requestJsonStr = JSON.toJSONString(request);
        multipartEntityBuilder.addPart("data", new StringBody(requestJsonStr, ContentType.APPLICATION_JSON));
        //签名值
        multipartEntityBuilder.addPart("sign", new StringBody(sign, ContentType.APPLICATION_JSON));
        HttpEntity reqEntity = multipartEntityBuilder.build();
        httppost.setEntity(reqEntity);
        CloseableHttpResponse httpResponse = null;
        HttpEntity resEntity = null;
        CloseableHttpClient httpClient = null;
        try {
            httpClient = HttpClients.createDefault();
            httpResponse = httpClient.execute(httppost);
            resEntity = httpResponse.getEntity();
            responseStr = EntityUtils.toString(resEntity, SignUtil.DEFAULT_CHARSET);
            long totalTimeCost = System.currentTimeMillis() - costTimeStart;
            log.info("直连乐刷 >> share >> 请求结束 >> 耗时={}ms, url={}, request={},       response={}",  totalTimeCost, url, requestJsonStr, responseStr);
            LeshuaBaseResponse<T> response = new LeshuaBaseResponse<>();
            JSONObject jsonObject = JSON.parseObject(responseStr);
            response.setReqSerialNo(jsonObject.getString("reqSerialNo"));
            response.setRespCode(jsonObject.getString("respCode"));
            response.setRespMsg(jsonObject.getString("respMsg"));
            response.setVersion(jsonObject.getString("version"));
            if (url.equals(JSON_ARRAY_URL_LIST)) {
                JSONArray dataList = JSON.parseArray(jsonObject.getString("data"));
                //把json数据放入到list中
                List list = new ArrayList<>();
                if (dataList != null) {
                    for (Object str : dataList) {
                        list.add(str);
                    }
                }
                response.setData((T) list);
            } else {
                response.setData(JSON.parseObject(jsonObject.getString("data"), request.getResponseClass()));
            }

            log.info("请求乐刷接口返回参数:{}", response);
            return response;
        } catch (Exception e) {
            long totalTimeCost = System.currentTimeMillis() - costTimeStart;
            log.error("直连乐刷 >> share >> 请求机构接口异常 >> 耗时={}ms, url={}, request={},       response={}", totalTimeCost, url, requestJsonStr, responseStr);
            throw new LeshuaException("调用失败", e);
        } finally {
            try {
                EntityUtils.consume(resEntity);
            } catch (IOException e) {
                log.error("释放HttpEntity出错，错误信息：" + e.getMessage(), e);
            }
            if (httpResponse != null) {
                try {
                    httpResponse.close();
                } catch (IOException e) {
                    log.error("关闭HttpResponse出错，错误信息：" + e.getMessage(), e);
                }
            }
        }
    }

}
